# -*- coding: utf-8 -*-
from objetos.Objeto import Objeto
from heroe import Heroe
from logico.problemas.acciones.ITener import ITener
from logico.problemas.acciones.ITenerOscuro import ITenerOscuro
from logico.problemas.acciones.ITenerParticula import ITenerParticula
from acciones.IAccion import IAccion
class Escena(Objeto):
	
	"""
	Objeto generico para representar un problema. Contiene una descripcion, un listado de objetos y la referencia a un Heroe prefabricado para dicho problema.
	@since: 4/14/2011
	@version: 1.0
	"""
	
	""" Nombre de la Escena """
	__nombre = "Escena_001"
	
	""" Descripcion del problema """
	__descripcion = ""
	
	""" Diccionario de objetos que la Escena contiene """
	__objetos = {}
	
	""" Heroe de la Escena """
	__heroe = None
	
	""" URL de la imagen de fondo de la escena """
	__background = ""
	
	""" Bandera para mostrar las flechas del IDE """
	__muestraFlechas=False
	
	def __init__(self, nombre, descripcion, objetos, imagen, ref_heroe, muestraFlechas=False):
		"""
		Constructor
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nombre: string
		@param	nombre: nombre del objeto representado.
		
		@type	descripcion: string
		@param	descripcion: descripcion de la escena / problema.
		
		@type	objetos: dictionary
		@param	objetos: diccionario de nombre --> objetos contenidos en la Escena/problema.
		
		@type	imagen: string
		@param	imagen: URL de la imagen de fondo
		
		@type	ref_heroe: Heroe
		@param	ref_heroe: Heroe de la Escena inicializado previamente.
		"""
		self.__nombre = nombre
		self.__descripcion = descripcion
		self.__objetos = objetos
		print objetos
		self.__heroe = ref_heroe
		self.__muestraFlechas=muestraFlechas
		Objeto.setImagen(self, imagen)
	
	def setBackgound(self, backgroundName):
		"""
		Asigna una imagen de fondo a la Escena.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	backgroundName: string
		@param	backgroundName: URL de la imagen de fondo
		"""
		self.__background = backgroundName
	
	def getBackground(self):
		"""
		Obtiene la imagen de fondo a la Escena.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return self.__background
	
	def getAcciones(self, nombreObjeto):
		"""
		Devuelve las acciones que se pueden realizar sobre un objeto indicado
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nombreObjeto: string
		@param	nombreObjeto: nombre del objeto al que queremos acceder.
		"""
		acciones = []
		objeto = self.getObjeto(nombreObjeto)
		for tupla in type(objeto).__mro__:
			try:
					#crea una instancia la clase
					instancia = tupla()
					
					#verifica que no sea Objeto ni object
					if(instancia.__class__.__name__!=objeto.__class__.__name__ and instancia.__class__.__name__ != 'Objeto' and instancia.__class__.__name__ != 'object'):
							#trae las acciones de la intancia
							acciones.extend(instancia.getAcciones(objeto, self.__heroe))
			except:
					pass
				
		objetos=[]
		if(isinstance(objeto, ITenerParticula)):
			if(objeto.getParticula()!=None):
				objetos=[objeto.getParticula()]
		else:
			if(isinstance(objeto, ITener)):
				objetos=objeto.getObjetos()
		
		for obj in objetos:
			for accion in self.getAccionesObjeto(obj):
				if(isinstance(accion, IAccion) and accion.esHeredable()):
					acciones.extend([accion])

		return acciones
	
	def getDiccionarioObjetos(self):
		"""
		Obtiene la relacion nombre --> objeto contenida en la Escena
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		objetos=self.getObjetos()
		diccionario={}
		for objeto in objetos:
			try:
				if (diccionario.has_key(objeto.getNombre())==False):
					diccionario.update({objeto.getNombre(): objeto});	
			except:
				pass
			
		return diccionario
	
	def getAccionesObjeto(self, objeto):
		"""
		Regresa las acciones dado un objeto
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	objeto: Objeto
		@param	objeto: objeto a analizar para buscar sus acciones.
		"""
		acciones = []
		nombre=objeto.getNombre()
		for tupla in type(objeto).__mro__:
			try:
					#crea una instancia la clase
					instancia = tupla(nombreObjeto=nombre)
					
					#verifica que no sea Objeto ni object
					if(instancia.__class__.__name__!=objeto.__class__.__name__ and instancia.__class__.__name__ != 'Objeto' and instancia.__class__.__name__ != 'object'):
							#trae las acciones de la intancia
							acciones.extend(instancia.getAcciones(objeto, self.__heroe))
			except:
					pass
				
		return acciones
					
	def getNombre(self):
		"""
		Obtiene el nombre de la Escena.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return self.__nombre

	def getDescripcion(self):
		"""
		Obtiene la descripcion de la Escena.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return self.__descripcion

	def getObjeto(self, nombre):
		"""
		Obtiene la referencia al objeto contenido en la Escena, segun su nombre.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nombre: string
		@param	nombre: nombre del objeto a buscar y traer.
		"""
		objetos = self.getObjetos()
		
		for o in objetos:
			if o.getNombre() == nombre:
				return o
	
	def popObjeto(self, nombre):
		"""
		???????
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nombre: string
		@param	nombre: nombre del objeto a tratar
		"""
		#no existe el objeto entre los no contenibles?
		if(not self.__objetos.has_key(nombre)):
			#recorremos todos los objetos de la escena
			for o in self.__objetos.values():
				#es instancia de IContener?
				if(isinstance(o, ITener)):
					if(o.existeObjeto(nombre)):
						return o.saco(nombre)
					else:
						return None
		else:
			return self.__objetos[nombre]
			
	def getObjetos(self, objetos=None):
		"""
		Devuelve una lista de objetos, los contenidos en la Escena.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		lista = []
		diccionario=False
		
		if objetos==None:
			objetos=self.__objetos.values()
			objetos.extend(self.__heroe.getObjetos())
			diccionario=True
		
		# Agregar contenedores y objetos contenidos (en orden, para la presedencia de dibujo en pantalla)
		for o in objetos:
			#es instancia de IContener?
			if(isinstance(o, ITenerParticula)):
				lista_tmp = []
				lista_tmp.append(o)
				if(o.getParticula()!=None):
					lista_tmp.append(o.getParticula())
				lista.extend(lista_tmp)
			else:
				if(isinstance(o, ITener)):
					lista_tmp = []
					lista_tmp.append(o)
					lista_tmp.extend(self.getObjetos(o.getObjetos()))
					lista.extend(lista_tmp)
					
		#es diccionario?		
		if diccionario:
			# Agregar objetos no contenidos
			for o in self.__objetos.values():
				if not(o  in lista):
					lista.append(o)
			
		return lista
	
	def getObjetosO1(self):
		
		"""
		Regresa una lista de los objetos contenedores oscuros en el primer nivel.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		lista = []
		
		#Traer todos los objetos en contenedores oscuros de primer nivel
		for o in self.__objetos.values():
			#es instancia de ITenerOscuro?
			if(isinstance(o, ITenerOscuro)):
				lista.extend(o.getObjetos())
				
		return lista
		
	def getPropiedad(self, objeto, propiedad):
		"""
		Obtiene una propiedad del objeto dado
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	objeto: string
		@param	objeto: nombre del objeto
		
		@type	propiedad: string
		@param	propiedad: nombre de la propiedad a buscar
		"""
		instancia=None
		
		try:
			instancia = self.__objetos[objeto];
		except:
			pass
		
		if(instancia==None):
			instancia=self.getObjeto(objeto)
			
		valor = None
		exec('valor=instancia.' + propiedad + '()')
		return valor
	
	def setPropiedad(self, objeto, propiedad, parametros):
		"""
		Asigna una propiedad del objeto dado
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	objeto: string
		@param	objeto: nombre del objeto
		
		@type	propiedad: string
		@param	propiedad: nombre de la propiedad a asignar
		
		@type	parametros: string
		@param	parametros: lista de parametros a asignar (separaos por comas)
		"""
		instancia=None
		
		try:
			instancia = self.__objetos[objeto];
		except:
			pass
		
		if(instancia==None):
			instancia=self.getObjeto(objeto)
			
		exec('instancia.' + propiedad + '(' + parametros + ')')

	def setNombre(self, nombre):
		"""
		Asigna el nombre a la Escena
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nombre: string
		@param	nombre: nuevo nombre de la Escena
		"""
		self.__nombre = nombre

	def setDescripcion(self, descripcion):
		"""
		Asigna una descripcion a la Escena
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	descripcion: string
		@param	descripcion: frase o parrafo que describa el problema representado por la Escena
		"""
		self.__descripcion = descripcion

	def getHeroe(self):
		"""
		Obtiene el Heroe de la Escena
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return self.__heroe
		
	def setHeroe(self, nu_heroe):
		"""
		Asigna un nuevo Heroe a la Escena
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	nu_heroe: Heroe
		@param	nu_heroe: referencia al nuevo Heroe de la Escena
		"""
		self.__heroe = nu_heroe
		
	def setMuestraFlechas(self, muestraFlechas):
		"""
		Metodo que permite indicar si las flechas del IDE son visibles o no. True = Visible, False = Invisible.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	muestraFlechas: Boolean
		@param	muestraFlechas: indica si se deben mostrar las flechas o no
		"""
		self.__muestraFlechas = muestraFlechas
	
	def getMuestraFlechas(self):
		"""
		Metodo que permite saber si las flechas del IDE son visibles o no. True = Visible, False = Invisible.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return self.__muestraFlechas
		
	def califica(self):
		"""
		Regresa una lista de observaciones segun el progreso (parcial o completo) del desarrollo del usuario en el problema.
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		"""
		return []
		
	def cumpleProp(self, objeto, propiedad, valor_esperado):
		"""
		Verifica que un objeto cumpla una propiedad dada
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	objeto: Objeto
		@param	objeto: objeto a evaluar
		
		@type	propiedad: string
		@param	propiedad: propiedad a evaluar
		
		@type	valor_esperado: string
		@param	valor_esperado: valor esperado de la evaluacion
		"""
		tor = False		
		exec("tor = objeto."+propiedad+" == valor_esperado")
		return tor
		
	def cumpleContiene(self, contenedor, contenido):
		"""
		Verifica que un contenedor posea en su interior un elemento dado
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	contenedor: Contenedor
		@param	contenedor: objeto a evaluar sobre la contencion
		
		@type	contenido: Objeto
		@param	contenido: objeto a evaluar sobre ser contenido
		"""
		return contenedor.existeObjeto(contenido)
		
	def cumpleContieneNombre(self, contenedor, nombre_contenido):
		"""
		Verifica que un contenedor posea en su interior un elemento cuyo nombre es dado
		@type	self: Escena
		@param	self: referencia al objeto Escena actual
		
		@type	contenedor: Contenedor
		@param	contenedor: objeto a evaluar sobre la contencion
		
		@type	nombre_contenido: string
		@param	nombre_contenido: nombre del objeto a evaluar sobre ser contenido
		"""
		for i in contenedor.getObjetos():
			if i!=None and i.getNombre() == nombre_contenido:
				return True
			
		return False	
